package com.changgou.oauth.service.impl;

import com.changgou.oauth.config.AuthProperties;
import com.changgou.oauth.service.AuthService;
import com.changgou.oauth.domain.AuthToken;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Service;
import org.springframework.util.Base64Utils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.DefaultResponseErrorHandler;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.net.URI;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @Author: HuangFu
 * @Date: 2020/2/10 17:09
 * @Description:  认证服务类
 */
@Service
public class AuthServiceImpl implements AuthService {
    @Autowired
    private LoadBalancerClient loadBalancerClient;

    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private AuthProperties authProperties;

    @Value("${spring.application.name}")
    private String serviceId;

    @Override
    public AuthToken login(String username, String password) {
        //获取服务实例URi
        ServiceInstance choose = loadBalancerClient.choose(serviceId);
        URI uri = choose.getUri();
        String authUrl = uri.toString() +"/oauth/token";

        //封装请求头
        MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
        headers.add("Authorization",getHttpBasic(authProperties.getClientId(),authProperties.getClientSecret()));
        //封装请求体
        MultiValueMap<String, String> body = new LinkedMultiValueMap<>();
        body.add("grant_type","password");
        body.add("username",username);
        body.add("password",password);

        //封装请求实体
        HttpEntity<MultiValueMap<String,String>> httpEntity = new HttpEntity<>(body,headers);

        //设置响应处理
        restTemplate.setErrorHandler(new DefaultResponseErrorHandler(){
            @Override
            public void handleError(ClientHttpResponse response) throws IOException {
                //当响应的值为400或401时候也要正常响应，不要抛出异常
                if(response.getRawStatusCode()!= 400 && response.getRawStatusCode() !=401){
                    super.handleError(response);
                }
            }
        });

        //发送请求
        ResponseEntity<Map> exchange = restTemplate.exchange(authUrl, HttpMethod.POST, httpEntity, Map.class);
        Map resultMap = exchange.getBody();
        //确保数据的完整性
        if(resultMap == null || resultMap.get("access_token")==null || resultMap.get("refresh_token")==null || resultMap.get("jti")==null){
            throw new RuntimeException("令牌请求失败");
        }

        //封装
        AuthToken authToken = new AuthToken();
        authToken.setAccessToken((String) resultMap.get("access_token"));
        authToken.setRefreshToken((String) resultMap.get("refresh_token"));
        authToken.setJti((String) resultMap.get("jti"));

        //存储到redis
        stringRedisTemplate.boundValueOps(authToken.getJti()).set(authToken.getAccessToken(),authProperties.getTtl(), TimeUnit.SECONDS);

        return authToken;
    }

    /**
     * 获取HttpBasic
     * @param clientId
     * @param clientSecret
     * @return
     */
    private String getHttpBasic(String clientId, String clientSecret) {
        String value =clientId+":"+clientSecret;
        byte[] encode = Base64Utils.encode(value.getBytes());
        return "Basic "+new String(encode);
    }
}
